package cn.billy.basic.service.impl;

import cn.billy.basic.constant.BaseConstants;
import cn.billy.basic.dto.RegisterDto;
import cn.billy.basic.exception.BusinessException;
import cn.billy.basic.service.IVerifyCodeService;
import cn.billy.basic.utils.Base64Util;
import cn.billy.basic.utils.SendMsg_webchinese;
import cn.billy.basic.utils.StrUtils;
import cn.billy.basic.utils.VerifyCodeUtils;
import cn.billy.user.domain.User;
import cn.billy.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;
    
    @Autowired
    private UserMapper userMapper;



    @Override
    public String graph(String key) {
        if (StringUtils.isEmpty(key)){
            throw new BusinessException("请传递必要的参数");
        }
        String code = StrUtils.getComplexRandomString(4);
        redisTemplate.opsForValue().set(key,code,5, TimeUnit.MINUTES);

        String Base64 = VerifyCodeUtils.VerifyCode(100, 35, code);
        return Base64;
    }

    @Override
    public void smsCode(RegisterDto registerDto) {
        // 获取参数
        String phone = registerDto.getPhone();

        // 业务类型type
        String type = registerDto.getType();
        //1.非空校验
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(type)){
            throw new BusinessException("参数不能为空！");
        }
        // 2.判断是走那个业务方法
        // 2.1.注册业务
        if ("register".equals(type)){
            // 校验图形验证码是否正确
            checkImageCode(registerDto);
            //3.判断用户是否已注册，如果已注册提示用户
            User user = userMapper.getByPhone(phone);
            if (user != null){
                throw new BusinessException("用户已注册，请直接登录，如果忘记密码，请点击忘记密码！");
            }
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX, phone);
        }else if ("binder".equals(type)){ // 2.2.微信绑定账号业务,发送短信验证码
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_PREFIX, phone);
        }

    }

    public void checkImageCode(RegisterDto registerDto){
        // 图形验证码的key
        String imageCodeKey = registerDto.getImageCodeKey();
        // 图形验证码的value
        String imageCodeValue = registerDto.getImageCodeValue();
        //1.非空校验
        if (StringUtils.isEmpty(imageCodeKey) || StringUtils.isEmpty(imageCodeValue)){
            throw new BusinessException("参数不能为空！");
        }
        //2.判断图形验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);
        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码已过期，请重新获取！");
        }
        // 忽略大小写比较图形验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码错误，请重新输入！");
        }
    }

    public void sendCode(String businessKey, String phone){
        //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String phoneCodeKey = businessKey + phone;
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);
        //0.定义一个空字符串，专门用来接收验证码
        String phoneCode = "";
        if (phoneCodeValue == null){//1.不存在
            //1.生成新的随机验证码,并赋值给空字符串
            phoneCode = StrUtils.getComplexRandomString(4);
        }else {//2.存在
            //1.分割value得到时间戳，跟现在的时间戳做减法，如果小于1分钟的毫秒数抛出异常
            String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");
            // 之前存入code时，我们记录的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 现在的时间戳
            Long nowTime = System.currentTimeMillis();
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟之后再获取！");
            }
            //2.将旧的验证码赋值给空字符串
            phoneCode = phoneCodeValueTmp[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);
        System.out.println("亲，您的验证码是："+ phoneCode);
    }



    @Override
    public void emailCode(RegisterDto registerDto) {
        // 获取用户输入的邮箱号
        String email = registerDto.getEmail();
        // 图形验证码的key
        String emailImageCodeKey = registerDto.getEmailImageCodeKey();
        // 图形验证码的value
        String emailImageCodeValue = registerDto.getEmailImageCodeValue();
        // 判断邮箱号是否为空
        if (StringUtils.isEmpty(email)){
            throw new BusinessException("邮箱名为空！请填写邮箱名！");
        }
        // 判断图形验证码是否为空
        if (StringUtils.isEmpty(emailImageCodeValue)){
            throw new BusinessException("验证码为空！请填写验证码！");
        }
        User user = userMapper.loadByEmail(email);
        System.out.println("1111111:"+user);
        if (user != null){
            throw new BusinessException("邮箱已被注册，请直接登录");
        }
        // 判断redis中的key是否还存在（通过imageCodeKey来获取）
        Object tmpImageValue = redisTemplate.opsForValue().get(emailImageCodeKey);
        // 如果不存在，则为3分钟有效期已过
        if (tmpImageValue == null){
            throw new BusinessException("图形验证码已过期，请重新获取！");
        }
        // 比较图形验证码是否输入正确（不区分大小写）
        if (!tmpImageValue.toString().equalsIgnoreCase(emailImageCodeValue)){
            throw new BusinessException("图形验证码输入错误，请重新输入！");
        }
        // 通过业务键邮箱号的形式，来给邮箱号注册设置唯一值
        String emailCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX + email;
        // 获取redis中的缓存
        Object emaileCodeValue = redisTemplate.opsForValue().get(emailCodeKey);
        String emailCode = "";
        // 如果为空
        if (emaileCodeValue == null){
            // 则生成4位随机数，赋值给phoneCode
            emailCode = StrUtils.getComplexRandomString(4);
        }else {
            // 如果已经获取过验证码，则判断是否为一分钟内获取的
            String[] phoneCodeValueTmp = emaileCodeValue.toString().split(":");
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            Long newTime = System.currentTimeMillis();
            if (newTime - oldTime < 1 * 60 * 1000){
                throw new BusinessException("操作过于频繁，请稍后获取！");
            }
            // 如果不是1分钟内获取的，则将之前的验证码重新赋值给phoneCode
            emailCode = phoneCodeValueTmp[1];
        }
        // 将时间戳+验证码组成redis的value
        String emailRedisValue = System.currentTimeMillis() + ":" + emailCode;
        // phoneCodeKey（业务键+手机号）作为key，phoneRedisValue（时间戳+验证码）作为value，缓存至redis，设置有效期为3分钟
        redisTemplate.opsForValue().set(emailCodeKey,emailRedisValue,3,TimeUnit.MINUTES);
        // 通过工具类发送验证短信
        System.out.println("您的验证码为" + emailCode + ",请在三分钟内输入。");
    }
}
